package com.rookie.data.generate.service;

import com.rookie.data.generate.component.BaseGenerate;
import com.rookie.data.generate.component.BeanContainer;
import com.rookie.data.generate.component.GenerateScanRegister;
import com.rookie.data.generate.constant.ResponseResult;
import com.rookie.data.generate.mapper.SystemMapper;
import com.rookie.data.generate.model.dto.InsertGenerateDTO;
import com.rookie.data.generate.model.dto.MultiplyTableDTO;
import com.rookie.data.generate.model.project.TableColumnEntity;
import com.rookie.data.generate.util.ResultUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class SystemService {

    @Resource
    private SystemMapper systemMapper;

    @Lazy
    @Autowired
    private SystemService systemService;

    private static final List<String> IGNORE_KEY = Arrays.asList("VIRTUAL GENERATED", "STORED GENERATED");

    public ResponseResult<String> insertAllTableData(Integer times) {
        if (times == null || times < 1) {
            return ResultUtils.error("生成数据条数参数异常");
        }
        List<String> tables = systemMapper.listTable();
        if (tables.size() > 0) {
            tables.forEach(p -> {
                insertData(p, times);
            });
        }
        return ResultUtils.success();
    }

    public ResponseResult<String> insertMultiplyTableData(MultiplyTableDTO param) {
        if (param.getTimes() == null) {
            param.setTimes(1);
        }
        if (param.getTableList() == null || param.getTableList().size() < 1) {
            return ResultUtils.error("生成的表配置不能为空");
        }
        for (MultiplyTableDTO.InnerTable innerTable : param.getTableList()) {
            if (StringUtils.isBlank(innerTable.getTable())) {
                continue;
            }
            int rowCount = innerTable.getTimes() == null ? param.getTimes() : innerTable.getTimes();
            insertData(innerTable.getTable(), rowCount);
        }
        return ResultUtils.success();
    }

    public ResponseResult<String> insertData(String tableName, Integer times) {
        int maxTimes = 4000;
        String message = "";
        if (StringUtils.isBlank(tableName)) {
            return ResultUtils.error("表名不能为空");
        }
        if (times == null || times < 1) {
            return ResultUtils.error("生成数据条数参数异常");
        }
        List<TableColumnEntity> tableColumn = systemMapper.listTableColumn(tableName);
//        生成数据太长的次数
        int errorTimes = 0;
//        最多 20 次
        int maxErrorTimes = 20;
        if (times > maxTimes) {
            int processNum = times / maxTimes;
            int lastTimes = times % maxTimes;
            if (lastTimes != 0) {
                processNum++;
            }
            for (int i = 0; i < processNum; i++) {
                if (i == processNum - 1) {
                    message = insertSingleTable(tableName, lastTimes == 0 ? maxTimes : lastTimes, tableColumn);
                } else {
                    message = insertSingleTable(tableName, maxTimes, tableColumn);
                }
                if (errorTimes > maxErrorTimes) {
                    return ResultUtils.error("生成数据长度超出范围次数太多，请调整一次生成数据的大小");
                }
//                生成的数据长度太长，重新生成
                if ("-1".equals(message)) {
                    i--;
                    errorTimes++;
                    continue;
                }
                if (StringUtils.isNotBlank(message)) {
                    return ResultUtils.error(message);
                }
            }
        } else {
            message = insertSingleTable(tableName, times, tableColumn);
            if (StringUtils.isNotBlank(message)) {
                return ResultUtils.error(message);
            }
        }
        return ResultUtils.success();
    }

    private String insertSingleTable(String tableName, Integer times, List<TableColumnEntity> tableColumn) {
        if (times < 1) {
            return null;
        }
        if (tableColumn.size() < 1) {
            return "当前表不存在";
        }
        if (tableColumn.size() == 1 && "auto_increment".equals(tableColumn.get(0).getExtra())) {
            return null;
        }

        InsertGenerateDTO insertGenerate = new InsertGenerateDTO();
        insertGenerate.setTableColumn(tableColumn)
                .setTableName(tableName)
                .setTimes(times)
                .setIsReplace(true)
                .setHistoryData(null);
        StringBuilder stringBuilder = generateInsertSql(insertGenerate);

        if (stringBuilder.toString().getBytes().length > BeanContainer.SqlStringMaxSize) {
            log.error("数据生成长度太长：{}。正常范围应该是：{}", stringBuilder.toString().getBytes().length, BeanContainer.SqlStringMaxSize);
            return "-1";
        }

        Map<String, Object> map = new HashMap<>(1);
        map.put("sqlString", stringBuilder.toString());
        systemMapper.generateData(map);
        System.out.printf("%s插入数据%d条成功%n", tableName, times);

        return null;
    }

    private StringBuilder generateInsertSql(InsertGenerateDTO insertGenerate) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("insert");
        if (insertGenerate.getIsReplace()) {
            stringBuilder.append(" ignore into ");
        } else {
            stringBuilder.append(" into ");
        }
        stringBuilder.append(insertGenerate.getTableName())
                .append("(");
        for (int i = 0; i < insertGenerate.getTableColumn().size(); i++) {
            if ("auto_increment".equals(insertGenerate.getTableColumn().get(i).getExtra())) {
                continue;
            }
//            忽略虚拟键
            if (IGNORE_KEY.contains(insertGenerate.getTableColumn().get(i).getExtra())) {
                continue;
            }
            if (i == insertGenerate.getTableColumn().size() - 1) {
                stringBuilder.append("`").append(insertGenerate.getTableColumn().get(i).getColumnName()).append("`").append(")");
            } else {
                stringBuilder.append("`").append(insertGenerate.getTableColumn().get(i).getColumnName()).append("`").append(",");
            }
        }
        stringBuilder.append(" values");
        for (int i = 0; i < insertGenerate.getTimes(); i++) {
            generateTableValue(insertGenerate.getTableName(), insertGenerate.getTableColumn(), stringBuilder, insertGenerate.getHistoryData());
            if (i != insertGenerate.getTimes() - 1) {
                stringBuilder.append(",");
            }
        }
        return stringBuilder;
    }

    public void dependentSqlInsert(String mainTable, String[] meanTable, List<TableColumnEntity> tableColumn) {
        String primaryKeyName = "id";

        Map<String, Object> historyData = new HashMap<>();
        InsertGenerateDTO insertGenerate = new InsertGenerateDTO();
        insertGenerate.setTableColumn(tableColumn)
                .setTableName(mainTable)
                .setTimes(1)
                .setIsReplace(false)
                .setHistoryData(historyData);
        StringBuilder sql = generateInsertSql(insertGenerate);


        Map<String, Object> map = new HashMap<>(1);
        map.put("sqlString", sql.toString());
        systemMapper.generateData(map);
        if (map.get(primaryKeyName) != null) {
            historyData.put(mainTable + "." + primaryKeyName, map.get(primaryKeyName));
        }

        for (String s : meanTable) {
            tableColumn = systemMapper.listTableColumn(s);
            if (tableColumn.size() < 1) {
                throw new RuntimeException(s + "表不存在，请检查配置");
            }
            insertGenerate.setTableName(s)
                    .setTableColumn(tableColumn);
            sql = generateInsertSql(insertGenerate);
            map.put("sqlString", sql.toString());
            systemMapper.generateData(map);
            if (map.get(primaryKeyName) != null) {
                historyData.put(s + "." + primaryKeyName, map.get(primaryKeyName));
            }
        }

    }

    private void generateTableValue(String tableName, List<TableColumnEntity> tableColumn, StringBuilder stringBuilder, Map<String, Object> historyData) {
        boolean fromOtherColumnFlag = false;
        Map<String, String> columnValue = GenerateScanRegister.DEPENDENT_COLUMN.get(tableName);
        if (historyData != null && columnValue != null && columnValue.size() > 0) {
            fromOtherColumnFlag = true;
        }

        stringBuilder.append("(");
        for (int i = 0; i < tableColumn.size(); i++) {
            if ("auto_increment".equals(tableColumn.get(i).getExtra())) {
                continue;
            }
            if (IGNORE_KEY.contains(tableColumn.get(i).getExtra())) {
                continue;
            }
            Object generate = null;
            String extraValue = null;
            if (fromOtherColumnFlag) {
                extraValue = columnValue.get(tableColumn.get(i).getColumnName());
                if (StringUtils.isNotBlank(extraValue)) {
                    generate = historyData.get(extraValue);
                }
            }

            if (!fromOtherColumnFlag || StringUtils.isBlank(extraValue)) {
                generate = BaseGenerate.generate(tableColumn.get(i), GenerateScanRegister.getTableFieldProperties(tableName, tableColumn.get(i).getColumnName()));
            }


            if (fromOtherColumnFlag) {
                historyData.put(tableName + "." + tableColumn.get(i).getColumnName(), generate);
            }
            if (generate instanceof String) {
                stringBuilder.append("'")
                        .append(generate)
                        .append("'");
            } else {
                stringBuilder.append(generate);
            }
            if (i == tableColumn.size() - 1) {
                stringBuilder.append(")");
            } else {
                stringBuilder.append(",");
            }
        }
    }

    public ResponseResult<String> dependentGenerate(String table, Integer times) {
        if (StringUtils.isBlank(table)) {
            return ResultUtils.error("表名不能为空");
        }
        if (times == null || times < 1) {
            return ResultUtils.error("生成数据条数参数异常");
        }
        if (GenerateScanRegister.MEANTIME_TABLE.get(table) == null || GenerateScanRegister.MEANTIME_TABLE.get(table).length < 1) {
            return ResultUtils.error("当前表未配置关联生成，请使用常规生成");
        }

        systemService.dependentAppendData(times, table);

        return ResultUtils.success();
    }

    @Transactional(rollbackFor = Exception.class)
    public void dependentAppendData(Integer times, String tableName) {
        List<TableColumnEntity> tableColumn = systemMapper.listTableColumn(tableName);
        if (tableColumn.size() < 1) {
            throw new RuntimeException("当前表不存在");
        }
        for (int i = 0; i < times; i++) {
            try {
                systemService.dependentSqlInsert(tableName, GenerateScanRegister.MEANTIME_TABLE.get(tableName), tableColumn);
            } catch (Exception e) {
//                手动回滚事务
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            }
        }
    }
}
